package edu.csu.smartpark.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import edu.csu.smartpark.dao.ParkSpaceDAO;
import edu.csu.smartpark.model.DO.ParkSpaceDO;
import edu.csu.smartpark.model.PO.ParkSpacePO;
import edu.csu.smartpark.model.VO.PageVO;
import edu.csu.smartpark.model.common.BusinessException;
import edu.csu.smartpark.service.ParkSpaceService;
import edu.csu.smartpark.util.Constants;
import edu.csu.smartpark.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ParkSpaceServiceImpl implements ParkSpaceService {
    @Autowired
    private ParkSpaceDAO parkSpaceDAO;

    @Override
    public String createParkSpace(ParkSpaceDO parkSpaceDO) throws BusinessException{
        if (isSpaceNameExist(parkSpaceDO.getSpaceId(), parkSpaceDO.getName(), parkSpaceDO.getParentId())){
            log.info("space name {} is exist", parkSpaceDO.getName());
            throw new BusinessException(BusinessException.PARAMETERERROR, "space name is exist");
        }
        ParkSpacePO parkSpacePO = new ParkSpacePO();
        BeanUtils.copyProperties(parkSpaceDO, parkSpacePO);
        Map<String, Object> extra = new HashMap<>();
        if (parkSpaceDO.getTypeCode().equals(Constants.house)){
            extra.put("roomSize", parkSpaceDO.getRoomSize());
            extra.put("roomCapacity", parkSpaceDO.getRoomCapacity());
        }
        if (parkSpaceDO.getTypeCode().equals(Constants.parkSpaceChannel)){
            extra.put("direction", parkSpaceDO.getDirection());
        }
        if (parkSpaceDO.getTypeCode().equals(Constants.parkingArea)){
            extra.put("tollStandardId", parkSpaceDO.getTollStandardId());
        }
        parkSpacePO.setExtra(StringUtil.JsonToString(extra));

        // 设置空间path参数
        StringBuffer path = new StringBuffer();
        if (parkSpaceDO.getTypeCode().equals(Constants.area)){
            path.append(String.format("/%s", parkSpaceDO.getParentId()));
        }else {
            ParkSpacePO parentParkSpacePO = parkSpaceDAO.selectById(parkSpaceDO.getParentId());
            path.append(parentParkSpacePO.getPath());
            path.append(String.format("/%s", parkSpaceDO.getParentId()));
        }
        parkSpacePO.setPath(path.toString());
        int result = parkSpaceDAO.insert(parkSpacePO);
        if (result > 0){
            log.info("[mysql]: create space {} success", parkSpacePO.getId());
            return  parkSpacePO.getId();
        }
        log.warn("[mysql]: create space fail");
        throw new BusinessException(BusinessException.SERVERERROR, "[mysql]: create space fail");
    }

    @Override
    public int deleteParkSpace(String spaceId) throws BusinessException{
        UpdateWrapper<ParkSpacePO>  updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", spaceId).set("is_deleted", 1);
        int row = parkSpaceDAO.update(null, updateWrapper);
        if (row < 0){
            log.info("[mysql] delete space {} fail", spaceId);
            throw new BusinessException(BusinessException.SERVERERROR, "delete space fail");
        }
        log.info("[mysql] delete space {} success", spaceId);
        return 1;
    }

    @Override
    public int updateParkSpace(ParkSpaceDO parkSpaceDO) throws BusinessException {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", parkSpaceDO.getSpaceId());
        ParkSpacePO parkSpacePO = parkSpaceDAO.selectOne(queryWrapper);
        if (parkSpacePO == null){
            log.warn("park space {} is null, update fail", parkSpaceDO.getSpaceId());
            throw new BusinessException(BusinessException.PARAMETERERROR, "park space {} is null, update fail");
        }
        if (parkSpaceDO.getName() != null && !parkSpaceDO.getName().equals("")){
            if (isSpaceNameExist(parkSpaceDO.getSpaceId(), parkSpaceDO.getName(), parkSpacePO.getParentId())){
                log.info("space name {} is exist", parkSpaceDO.getName());
                throw new BusinessException(BusinessException.PARAMETERERROR, "space name is exist");
            }
            parkSpacePO.setName(parkSpaceDO.getName());
        }
        Map<String, Object> extra = StringUtil.parseJsonString(parkSpacePO.getExtra());
        if (parkSpaceDO.getRoomSize() != null){
            if (!parkSpacePO.getTypeCode().equals(Constants.house)) {
                log.info("modify space {} fail, this space has not room size attribute", parkSpaceDO.getName());
                throw new BusinessException(BusinessException.PARAMETERERROR, String.format("modify space %s fail, this space has not room size attribute",parkSpaceDO.getName()));
            }
            extra.put("roomSize", parkSpaceDO.getRoomSize());
        }

        if (parkSpaceDO.getRoomCapacity() != null){
            if (!parkSpacePO.getTypeCode().equals(Constants.house)) {
                log.info("modify space {} fail, this space has not room capacity attribute", parkSpaceDO.getName());
                throw new BusinessException(BusinessException.PARAMETERERROR, String.format("modify space %s fail, this space has not room capacity attribute", parkSpaceDO.getName()));
            }
            extra.put("roomCapacity", parkSpaceDO.getRoomCapacity());
        }

        if (parkSpaceDO.getDirection() != null){
            if (!parkSpacePO.getTypeCode().equals(Constants.parkSpaceChannel)) {
                log.info("modify space {} fail, this space has not  direction attribute", parkSpaceDO.getName());
                throw new BusinessException(BusinessException.PARAMETERERROR, String.format("modify space %s fail, this space has not direction attribute", parkSpaceDO.getName()));
            }
            if (parkSpaceDO.getDirection() != 0 && parkSpaceDO.getDirection() != 1) {
                log.info("modify space {} fail, direction value {} is invalid", parkSpaceDO.getName(), parkSpaceDO.getDirection());
                throw new BusinessException(BusinessException.PARAMETERERROR, String.format("modify space %s fail, direction value should be 0 or 1", parkSpaceDO.getName()));
            }
            extra.put("direction", parkSpaceDO.getDirection());
        }

        if (parkSpaceDO.getTollStandardId() != null){
            if (!parkSpaceDO.getTypeCode().equals(Constants.parkingArea)){
                log.info("modify space {} fail, this space has not  direction attribute", parkSpaceDO.getName());
            }
            // TODO 校验收费标准是否存在
            extra.put("tollStandardId", parkSpaceDO.getTollStandardId());
        }

        parkSpacePO.setExtra(StringUtil.JsonToString(extra));
        int res = parkSpaceDAO.updateById(parkSpacePO);
        if (res <=0){
            log.info("[mysql] update space {} fail", parkSpacePO.getId());
            throw new BusinessException(BusinessException.SERVERERROR, "update space fail");
        }
        return 1;
    }

    @Override
    public PageVO<ParkSpaceDO> getSubSpaceList(int pageNum, int pageSize, String spaceId, String typeCode) throws BusinessException{
        QueryWrapper<ParkSpacePO> queryWrapper = new QueryWrapper<>();
        if (spaceId != null && !spaceId.equals("")){
            queryWrapper.like("path", spaceId);
        }
        queryWrapper.eq("type_code", typeCode);
        queryWrapper.eq("is_deleted", 0);
        Page<ParkSpacePO> page = new Page<>(pageNum, pageSize);
        IPage<ParkSpacePO> parkSpaces = parkSpaceDAO.selectPage(page, queryWrapper);
        List<ParkSpacePO> recordPOs = parkSpaces.getRecords();
        List<ParkSpaceDO> recordDOs = new LinkedList<>();
        for (ParkSpacePO recordPO: recordPOs){
            ParkSpaceDO recordDO = new ParkSpaceDO();
            BeanUtils.copyProperties(recordPO, recordDO);
            recordDO.setSpaceId(recordPO.getId());
            if (recordPO.getExtra() != null){
                Map<String, Object> extra = StringUtil.parseJsonString(recordPO.getExtra());
                recordDO.setDirection((Integer) extra.getOrDefault("direction", null));
                recordDO.setRoomSize((Integer)extra.getOrDefault("roomSize", null));
                recordDO.setRoomCapacity((Integer)extra.getOrDefault("roomCapacity", null));
                recordDOs.add(recordDO);
            }
        }
        PageVO<ParkSpaceDO> pageVO = new PageVO<>();
        pageVO.setTotal(parkSpaces.getTotal());
        pageVO.setPageSize(recordDOs.size());
        pageVO.setPageNum(parkSpaces.getCurrent());
        pageVO.setPages(parkSpaces.getPages());
        pageVO.setRecords(recordDOs);
        log.info("[mysql] get sub space {} {} list success", spaceId, typeCode);
        return pageVO;
    }

    @Override
    public Map<String, ParkSpaceDO> getSpaceInfos(List<String> spaceIds) throws BusinessException{
        List<ParkSpacePO> parkSpacePOS = parkSpaceDAO.selectBatchIds(spaceIds);
        Map<String, ParkSpaceDO> result = new HashMap<>();
        for (ParkSpacePO parkSpacePO : parkSpacePOS){
            ParkSpaceDO parkSpaceDO = new ParkSpaceDO();
            BeanUtils.copyProperties(parkSpacePO, parkSpaceDO);
            parkSpaceDO.setSpaceId(parkSpacePO.getId());
            if (parkSpacePO.getExtra() != null){
                Map<String, Object> extra = StringUtil.parseJsonString(parkSpacePO.getExtra());
                parkSpaceDO.setDirection((Integer) extra.getOrDefault("direction", null));
                parkSpaceDO.setRoomSize((Integer)extra.getOrDefault("roomSize", null));
                parkSpaceDO.setRoomCapacity((Integer)extra.getOrDefault("roomCapacity", null));
                result.put(parkSpaceDO.getSpaceId(), parkSpaceDO);
            }
        }
        return result;
    }

    @Override
    public List<ParkSpaceDO> getSpaceInfoByName(String spaceName) throws BusinessException{
        QueryWrapper<ParkSpacePO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", spaceName);
        queryWrapper.eq("is_deleted", 0);
        List<ParkSpacePO> parkSpacePOs = parkSpaceDAO.selectList(queryWrapper);
        List<ParkSpaceDO> res = new LinkedList<>();
        for (ParkSpacePO parkSpacePO : parkSpacePOs){
            ParkSpaceDO parkSpaceDO = new ParkSpaceDO();
            BeanUtils.copyProperties(parkSpacePO, parkSpaceDO);
            parkSpaceDO.setSpaceId(parkSpacePO.getId());
            if (parkSpacePO.getExtra() != null){
                Map<String, Object> extra = StringUtil.parseJsonString(parkSpacePO.getExtra());
                parkSpaceDO.setDirection((Integer) extra.getOrDefault("direction", null));
                parkSpaceDO.setRoomSize((Integer)extra.getOrDefault("roomSize", null));
                parkSpaceDO.setRoomCapacity((Integer)extra.getOrDefault("roomCapacity", null));
            }
            res.add(parkSpaceDO);
        }
        return res;
    }

    @Override
    /*
    * @Description: 根据名称判断空间是否已存在
    * @Author: LZY
    * @Date: 2021/6/8 17:02
    * @Params: [name, parentId]
    * @Return: boolean
    */
    public boolean isSpaceNameExist(String spaceId, String name, String parentId) throws BusinessException {
        List<ParkSpaceDO> parkSpaceDOs = getSpaceInfoByName(name);
        if (parkSpaceDOs.size() == 0){
            return false;
        }
        for (ParkSpaceDO parkSpaceDO : parkSpaceDOs){
            if (parkSpaceDO.getParentId().equals(parentId) && !parkSpaceDO.getSpaceId().equals(spaceId)){
                return true;
            }
        }
        return false;
    }
}
